﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows;
using DSLPedItemWizard;
using Dsl.Ped.Desktop.Messages;
using Dsl.Ped.Desktop.ModuleControllers;
using Dsl.Ped.Editor.Interfaces;
using Dsl.Ped.Framework.Common;
using Dsl.Ped.Framework.Messages;
using GalaSoft.MvvmLight.Messaging;
using System.ComponentModel.Composition.Hosting;

namespace Dsl.Ped.Desktop.Modules.Editor
{
    /// <summary>
    /// This is a class that controls the editor 
    /// </summary>
    public class EditorController : IModuleController
    {
        /// <summary>
        /// Instance of a <see cref="IDslPedEditor"/> that is controlled by this class
        /// </summary>
        private readonly IDslPedEditor dslPedEditor;

        /// <summary>
        /// Instantiates new <see cref="EditorController"/>
        /// </summary>
        /// <param name="dslPedEditor">Instance of <see cref="IDslPedEditor"/> that is gonna be controlled
        /// by this controller class</param>
        public EditorController(IDslPedEditor dslPedEditor)
        {
            // Set the controlled instance 
            this.dslPedEditor = dslPedEditor;
        }

        /// <summary>
        /// Start the controlling of the instance, generally register
        /// all required messages and start listening to them
        /// </summary>
        /// <param name="messenger"></param>
        public void Start(Messenger messenger)
        {
            messenger.Register<OpenFileMessage>(this, OnOpenFileMessage);
            messenger.Register<SaveFileMessage>(this, OnSaveFileMessage);
            messenger.Register<SaveFileAsMessage>(this, OnSaveFileAsMessage);
            messenger.Register<NewFileMessage>(this, OnNewFileMessage);
        }

        /// <summary>
        /// Stop the controller
        /// </summary>
        public void Stop()
        {

        }

        #region Methods

        /// <summary>
        /// Handler method executed when the <see cref="OpenFileMessage"/> is
        /// received. Invokes the opening of the Projective Object
        /// </summary>
        /// <param name="openFileMessage"><see cref="OpenFileMessage"/> instance</param>
        private void OnOpenFileMessage(OpenFileMessage openFileMessage)
        {
            if (openFileMessage == null) return;

            this.OpenProjectiveObject();
        }

        /// <summary>
        /// Handler method executed when the <see cref="SaveFileMessage"/> is 
        /// received. Invokes the saving of a current Projective Object
        /// under the current file name.
        /// </summary>
        /// <param name="saveFileMessage"><see cref="SaveFileMessage"/> instance</param>
        private void OnSaveFileMessage(SaveFileMessage saveFileMessage)
        {
            if (saveFileMessage == null) return;

            // If the current file is not specified yet, save the file as (in general
            // invoke the opening of "Save As" dialog
            if (dslPedEditor.CurrentFileName == null)
            {
                SaveAsProjectiveObject();
            }
            else
            {
                SaveProjectiveObject();
            }     
        }

        /// <summary>
        /// Handler method executed when the <see cref="SaveFileAsMessage"/> is
        /// received. Invokes the opening of "Save As" dialog to choose the name
        /// of a file under which the current Projective Object should be saved.
        /// </summary>
        /// <param name="saveFileAsMessage"><see cref="SaveFileAsMessage"/> instance</param>
        private void OnSaveFileAsMessage(SaveFileAsMessage saveFileAsMessage)
        {
            if (saveFileAsMessage == null) return;

            this.SaveAsProjectiveObject();
        }

        /// <summary>
        /// Handler method executed when the <see cref="NewFileMessage"/> is 
        /// received. Invokes the creation of a new Projective Object of a <see cref="Type"/>
        /// provided in FileType of the message.
        /// </summary>
        /// <param name="newFileMessage"><see cref="NewFileMessage"/> instance</param>
        private void OnNewFileMessage(NewFileMessage newFileMessage)
        {
            if (newFileMessage == null) return;

            // If the file type of the message is not specified, invoke displaying 
            // of the wizard to let the user choose from available types
            if (newFileMessage.FileType == null)
            {
                var addInsCatalog = new DirectoryCatalog(ApplicationResources.Instance.AddInsDirectory);
                var mainWizardWindow = new MainWizardWindow(addInsCatalog);
                var result = mainWizardWindow.ShowDialog();

                if (result == true)
                {
                    var type = mainWizardWindow.GetFileType();
                    var projectiveObject = mainWizardWindow.GetFileObject();
                    this.NewProjectiveObject(type, projectiveObject);
                }
            }
            // If the fileType is specified create an instance of the object
            else
            {
                // If the fileType is not provided with a default object
                // in the message, create a new instance of the object directly
                // from its type
                if (newFileMessage.DefaultObject == null)
                {
                    this.NewProjectiveObject(newFileMessage.FileType);    
                }
                // Else if the default object is provided in the message
                // use it for the creation of an object
                else
                {
                    this.NewProjectiveObject(newFileMessage.FileType, newFileMessage.DefaultObject);   
                }
            }
        }

        /// <summary>
        /// Opens a ProjectiveObject from the file chosen via an Open File Dialog
        /// </summary>
        private void OpenProjectiveObject()
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".xml"; // Default file extension 

            List<string> filterValues = new List<string>();
            /* foreach (var addIn in AddInRegistrationService.AddIns) {
                filterValues.Add(String.Format("*.{0}|*.{0}", addIn.Metadata.Extension));
            }*/
            filterValues.Add(String.Format("*.{0}|*.{0}", "dsl"));
            dlg.Filter = String.Join("|", filterValues);

            dlg.InitialDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            // Show open file dialog box 
            Nullable<bool> result = dlg.ShowDialog();

            // Process open file dialog box results 
            if (result == true)
            {
                // Open document 
                var fileName = dlg.FileName;
                var obj = this.dslPedEditor.LoadFile(fileName);

                if (obj != null)
                {
                    FrameworkMessenger.RegisterParent(obj);
                    var messenger = FrameworkMessenger.GetMessenger(obj);

                    IModuleController desktopController = new ErrorsNotificationController();
                    desktopController.Start(messenger);

                    this.dslPedEditor.OpenLoadedFile();
                }
            }
        }

        /// <summary>
        /// Save current Projective Object under the current file name
        /// </summary>
        private void SaveProjectiveObject()
        {
            dslPedEditor.SaveFile();
        }               

        /// <summary>
        /// Save current Projective Object under a new file name gathered from the
        /// "Save As" dialog
        /// </summary>
        private void SaveAsProjectiveObject()
        {
            if (dslPedEditor.CurrentProjectiveType == null)
            {
                MessageBox.Show("No file is opened to be saved", "No file to save", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();

            var filterValues = new List<string>();
            filterValues.Add(String.Format("*.{0}|*.{0}", "dsl"));

            dlg.Filter = String.Join("|", filterValues);

            dlg.InitialDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            // Show open file dialog box 
            Nullable<bool> result = dlg.ShowDialog();

            // Process open file dialog box results 
            if (result == true)
            {
                // Open document 
                string fileName = dlg.FileName;
                dslPedEditor.SaveFile(fileName);
            }
        }

        /// <summary>
        /// Create new projective object of a given type and initialize editor with it
        /// </summary>
        /// <param name="projectiveType">Projective type</param>
        private void NewProjectiveObject(Type projectiveType)
        {
            dslPedEditor.NewProjectiveObject(projectiveType);
        }

        /// <summary>
        /// Create new projective object of a given type and initialize editor with it
        /// </summary>
        /// <param name="projectiveType">Projective type</param>
        private void NewProjectiveObject(Type projectiveType, IProjective projectiveObject)
        {
            dslPedEditor.NewProjectiveObject(projectiveType, projectiveObject);
        }

        #endregion
    }
}
